#include "HiranipraShared.h"

#ifndef _SHARED_PLATFORM_IO_IOBUFFER_H_
#define _SHARED_PLATFORM_IO_IOBUFFER_H_

namespace Hiranipra {
	namespace Platform {
		namespace IO {

			class MemoryBuffer : implements RefInstance
			{
			public:
				MemoryBuffer( uint32 capacity = 0, bool zero = false ) :
					_size( capacity ),
					_buffer( NULL ), _isReadOnly( false ), _isWrapped( false )
				{
					if( capacity > 0 )
					{
						if( zero == true )
							_buffer = ( void* )calloc( capacity, sizeof( uint8 ) );
						else
							_buffer = ( void* )malloc( capacity );
						ASSERT( _buffer != NULL, "Unable to allocate buffer" );
					}
				}
				MemoryBuffer( void* sourceBuffer, uint32 sourceSize, bool readOnly = false ) :
					_size( sourceSize ),
					_buffer( NULL ), _isReadOnly( readOnly ), _isWrapped( false )
				{
					_buffer = ( void* )malloc( sourceSize );
					memcpy( _buffer, sourceBuffer, sourceSize );
				}
				virtual ~MemoryBuffer()
				{
					if( _isWrapped == false )
						FREE_PTR( _buffer );
					_buffer = NULL;
				}
				
				static MemoryBuffer* Wrap( void* sourceBuffer, uint32 sourceSize )
				{
					return new MemoryBuffer( true, sourceBuffer, sourceSize );
				}

				uint32 GetSize() const { return _size; }
				bool IsReadOnly() const { return _isReadOnly; }
				bool IsLocked() const { return _isLocked; }
				void* GetPointer() const
				{
					ASSERT( _isLocked == true, "Attempt to GetBuffer() while not locked" );
					if( _isLocked == false )
						return NULL;
					else
						return _buffer;
				}

				void* Lock( uint32* psize = NULL )
				{
					_lock.acquire();
					_isLocked = true;
					if( psize != NULL )
						*psize = _size;
					return _buffer;
				}

				void Unlock()
				{
					ASSERT( _isLocked == true, "Unmatched Unlock()" );
					_isLocked = false;
					_lock.release();
				}

				bool Resize( uint32 newSize, bool forceShrink = false )
				{
					ASSERT( _isLocked == true, "Attempt to Resize() while not locked" );
					if( _isLocked == false )
						return false;
					ASSERT( _isWrapped == false, "Attempt to Resize() a wrapped buffer" );
					if( _isWrapped == true )
						return false;
					ASSERT( _isReadOnly == false, "Attempt to Resize() a readonly buffer" );
					if( _isReadOnly == true )
						return false;
					if( newSize == _size )
						return true;
					if( ( forceShrink == false ) && ( newSize < _size ) )
						return true;
					void* buffer = realloc( _buffer, newSize );
					DASSERT( buffer != NULL, "Resize() failed to realloc" );
					if( buffer == NULL )
						return false;
					_buffer = buffer;
					_size = newSize;
					return true;
				}

			private:
				MemoryBuffer( bool wrap, void* sourceBuffer, uint32 sourceSize ) :
					_size( sourceSize ),
					_buffer( sourceBuffer ), _isReadOnly( true ), _isWrapped( true )
				{
				}

			private:
				uint32		_size;
				void*		_buffer;
				bool		_isReadOnly;
				bool		_isWrapped;
				
				bool		_isLocked;
				FastMutex	_lock;
			};

		}
	}
}

#endif // _SHARED_PLATFORM_IO_IOBUFFER_H_
